use std::fs;
use std::path::Path;
use serde::{Deserialize, Serialize};
use encoding_rs::{GBK, UTF_8};
use base64;

// GBK 解码函数
fn decode_gbk_or_utf8(bytes: &[u8]) -> String {
    // 首先尝试 GBK 解码
    let (decoded, _, had_errors) = GBK.decode(bytes);
    if !had_errors {
        return decoded.into_owned();
    }
    
    // 如果 GBK 解码失败，尝试 UTF-8
    let (decoded, _, had_errors) = UTF_8.decode(bytes);
    if !had_errors {
        return decoded.into_owned();
    }
    
    // 如果都失败，使用 lossy 解码
    String::from_utf8_lossy(bytes).to_string()
}

// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

#[derive(Debug, Serialize, Deserialize)]
pub struct FileItem {
    name: String,
    path: String,
    is_directory: bool,
    size: Option<u64>,
    extension: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct FileContent {
    content: String,
    path: String,
    is_binary: bool,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ImageContent {
    content: String,  // base64编码的图片数据
    path: String,
    mime_type: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CommandResult {
    success: bool,
    output: String,
    error: Option<String>,
    exit_code: Option<i32>,
    new_working_dir: Option<String>,
}

#[tauri::command]
async fn read_directory(path: String) -> Result<Vec<FileItem>, String> {
    let path = Path::new(&path);
    
    if !path.exists() {
        return Err("路径不存在".to_string());
    }
    
    if !path.is_dir() {
        return Err("路径不是目录".to_string());
    }
    
    let mut items = Vec::new();
    
    match fs::read_dir(path) {
        Ok(entries) => {
            for entry in entries {
                if let Ok(entry) = entry {
                    let path_buf = entry.path();
                    let name = path_buf.file_name()
                        .and_then(|n| n.to_str())
                        .unwrap_or("未知文件")
                        .to_string();
                    
                    let is_directory = path_buf.is_dir();
                    let size = if is_directory {
                        None
                    } else {
                        fs::metadata(&path_buf).ok().map(|m| m.len())
                    };
                    
                    let extension = path_buf.extension()
                        .and_then(|ext| ext.to_str())
                        .map(|s| s.to_string());
                    
                    items.push(FileItem {
                        name,
                        path: path_buf.to_string_lossy().to_string(),
                        is_directory,
                        size,
                        extension,
                    });
                }
            }
            
            // 按目录在前，文件在后的顺序排序
            items.sort_by(|a, b| {
                match (a.is_directory, b.is_directory) {
                    (true, false) => std::cmp::Ordering::Less,
                    (false, true) => std::cmp::Ordering::Greater,
                    _ => a.name.to_lowercase().cmp(&b.name.to_lowercase()),
                }
            });
            
            Ok(items)
        }
        Err(e) => Err(format!("读取目录失败: {}", e))
    }
}

#[tauri::command]
async fn read_file(path: String) -> Result<FileContent, String> {
    let path = Path::new(&path);
    
    if !path.exists() {
        return Err("文件不存在".to_string());
    }
    
    if !path.is_file() {
        return Err("路径不是文件".to_string());
    }
    
    // 获取文件大小
    let metadata = match fs::metadata(path) {
        Ok(meta) => meta,
        Err(e) => return Err(format!("获取文件信息失败: {}", e))
    };
    
    let file_size = metadata.len();
    const MAX_FILE_SIZE: u64 = 10 * 1024 * 1024; // 10MB限制
    
    // 检查文件大小
    if file_size > MAX_FILE_SIZE {
        return Err(format!("文件过大 ({} MB)，无法在编辑器中打开。建议使用其他工具查看此文件。", file_size / 1024 / 1024));
    }
    
    // 首先尝试读取为文本文件
    match fs::read_to_string(path) {
        Ok(content) => Ok(FileContent {
            content,
            path: path.to_string_lossy().to_string(),
            is_binary: false,
        }),
        Err(_) => {
            // 如果文本读取失败，尝试读取为二进制文件
            match fs::read(path) {
                Ok(bytes) => {
                    // 将二进制数据转换为字符串用于检测
                    let content = String::from_utf8_lossy(&bytes).to_string();
                    Ok(FileContent {
                        content,
                        path: path.to_string_lossy().to_string(),
                        is_binary: true,
                    })
                },
                Err(e) => Err(format!("读取文件失败: {}", e))
            }
        }
    }
}

#[tauri::command]
async fn read_image_file(path: String) -> Result<ImageContent, String> {
    let path = Path::new(&path);
    
    if !path.exists() {
        return Err("文件不存在".to_string());
    }
    
    if !path.is_file() {
        return Err("路径不是文件".to_string());
    }
    
    // 获取文件扩展名来确定MIME类型
    let extension = path.extension()
        .and_then(|ext| ext.to_str())
        .unwrap_or("")
        .to_lowercase();
    
    let mime_type = match extension.as_str() {
        "png" => "image/png",
        "jpg" | "jpeg" => "image/jpeg",
        "gif" => "image/gif",
        "bmp" => "image/bmp",
        "webp" => "image/webp",
        "svg" => "image/svg+xml",
        "ico" => "image/x-icon",
        _ => "image/png", // 默认
    };
    
    // 读取图片文件
    match fs::read(path) {
        Ok(bytes) => {
            // 将图片数据转换为base64编码
            let base64_content = base64::encode(&bytes);
            Ok(ImageContent {
                content: base64_content,
                path: path.to_string_lossy().to_string(),
                mime_type: mime_type.to_string(),
            })
        },
        Err(e) => Err(format!("读取图片文件失败: {}", e))
    }
}

#[tauri::command]
async fn write_file(path: String, content: String) -> Result<(), String> {
    let path = Path::new(&path);
    
    // 确保父目录存在
    if let Some(parent) = path.parent() {
        if !parent.exists() {
            if let Err(e) = fs::create_dir_all(parent) {
                return Err(format!("创建目录失败: {}", e));
            }
        }
    }
    
    match fs::write(path, content) {
        Ok(_) => Ok(()),
        Err(e) => Err(format!("写入文件失败: {}", e))
    }
}

#[tauri::command]
async fn get_current_directory() -> Result<String, String> {
    match std::env::current_dir() {
        Ok(path) => Ok(path.to_string_lossy().to_string()),
        Err(e) => Err(format!("获取当前目录失败: {}", e))
    }
}

#[tauri::command]
async fn select_folder() -> Result<Option<String>, String> {
    // 暂时返回当前目录
    match std::env::current_dir() {
        Ok(path) => Ok(Some(path.to_string_lossy().to_string())),
        Err(e) => Err(format!("获取当前目录失败: {}", e))
    }
}

#[tauri::command]
async fn open_file_with_system(path: String) -> Result<(), String> {
    use std::process::Command;
    
    let path = Path::new(&path);
    
    if !path.exists() {
        return Err("文件不存在".to_string());
    }
    
    #[cfg(target_os = "windows")]
    {
        Command::new("cmd")
            .args(&["/C", "start", "", &path.to_string_lossy()])
            .spawn()
            .map_err(|e| format!("打开文件失败: {}", e))?;
    }
    
    #[cfg(target_os = "macos")]
    {
        Command::new("open")
            .arg(&path.to_string_lossy())
            .spawn()
            .map_err(|e| format!("打开文件失败: {}", e))?;
    }
    
    #[cfg(target_os = "linux")]
    {
        Command::new("xdg-open")
            .arg(&path.to_string_lossy())
            .spawn()
            .map_err(|e| format!("打开文件失败: {}", e))?;
    }
    
    Ok(())
}

#[tauri::command]
async fn close_window(window: tauri::Window) -> Result<(), String> {
    window.close().map_err(|e| format!("关闭窗口失败: {}", e))
}

#[tauri::command]
async fn minimize_window(window: tauri::Window) -> Result<(), String> {
    window.minimize().map_err(|e| format!("最小化窗口失败: {}", e))
}

#[tauri::command]
async fn toggle_maximize_window(window: tauri::Window) -> Result<(), String> {
    if window.is_maximized().unwrap_or(false) {
        window.unmaximize().map_err(|e| format!("还原窗口失败: {}", e))
    } else {
        window.maximize().map_err(|e| format!("最大化窗口失败: {}", e))
    }
}

#[tauri::command]
async fn execute_command(command: String, args: Vec<String>, working_dir: Option<String>) -> Result<CommandResult, String> {
    use std::process::{Command, Stdio};
    use std::io::Read;
    use std::env;
    
    #[cfg(target_os = "windows")]
    use std::os::windows::process::CommandExt;
    
    // 获取当前工作目录
    let current_dir = working_dir.unwrap_or_else(|| {
        env::current_dir()
            .map(|p| p.to_string_lossy().to_string())
            .unwrap_or_else(|_| ".".to_string())
    });
    
    // 处理特殊命令
    match command.as_str() {
        "cd" => {
            if args.is_empty() {
                // 显示当前目录
                Ok(CommandResult {
                    success: true,
                    output: current_dir,
                    error: None,
                    exit_code: Some(0),
                    new_working_dir: None,
                })
            } else {
                // 计算新的工作目录
                let new_dir = if args[0] == ".." {
                    // 返回上级目录
                    let path = std::path::Path::new(&current_dir);
                    path.parent()
                        .map(|p| p.to_string_lossy().to_string())
                        .unwrap_or(current_dir)
                } else if args[0].starts_with('/') || args[0].contains(':') {
                    // 绝对路径
                    args[0].clone()
                } else {
                    // 相对路径
                    let path = std::path::Path::new(&current_dir).join(&args[0]);
                    path.to_string_lossy().to_string()
                };
                
                // 检查目录是否存在
                if std::path::Path::new(&new_dir).exists() {
                    Ok(CommandResult {
                        success: true,
                        output: format!("Changed directory to: {}", new_dir),
                        error: None,
                        exit_code: Some(0),
                        new_working_dir: Some(new_dir),
                    })
                } else {
                    Ok(CommandResult {
                        success: false,
                        output: String::new(),
                        error: Some(format!("Directory not found: {}", args[0])),
                        exit_code: Some(1),
                        new_working_dir: None,
                    })
                }
            }
        },
        "pwd" => {
            Ok(CommandResult {
                success: true,
                output: current_dir,
                error: None,
                exit_code: Some(0),
                new_working_dir: None,
            })
        },
        _ => {
            // 构建完整的命令字符串
            let full_command = if args.is_empty() {
                command.clone()
            } else {
                format!("{} {}", command, args.join(" "))
            };
            
            // 直接执行命令，避免cmd窗口一闪而过
            let mut cmd = if cfg!(target_os = "windows") {
                // 在Windows上，对于某些命令使用cmd，但避免窗口闪烁
                if command == "dir" || command == "type" || command == "copy" || 
                   command == "move" || command == "del" || command == "mkdir" || 
                   command == "rmdir" || command == "ver" || command == "date" || 
                   command == "time" || command == "ipconfig" || command == "ping" {
                    // 这些是cmd内置命令，需要使用cmd执行
                    let mut cmd = Command::new("cmd");
                    cmd.args(&["/c", &full_command])
                       .current_dir(&current_dir)
                       .stdout(Stdio::piped())
                       .stderr(Stdio::piped())
                       .stdin(Stdio::piped())
                       .creation_flags(0x08000000); // CREATE_NO_WINDOW 标志，隐藏控制台窗口
                    cmd
                } else {
                    // 其他命令直接执行，不使用cmd
                    let mut cmd = Command::new(&command);
                    cmd.args(&args)
                       .current_dir(&current_dir)
                       .stdout(Stdio::piped())
                       .stderr(Stdio::piped())
                       .stdin(Stdio::piped());
                    cmd
                }
            } else {
                // 在非Windows系统上直接执行命令
                let mut cmd = Command::new(&command);
                cmd.args(&args)
                   .current_dir(&current_dir)
                   .stdout(Stdio::piped())
                   .stderr(Stdio::piped())
                   .stdin(Stdio::piped());
                cmd
            };
            
            // 执行命令
            match cmd.spawn() {
                Ok(mut child) => {
                    // 等待命令完成
                    let status = child.wait().map_err(|e| format!("等待命令完成失败: {}", e))?;
                    
                    // 读取输出
                    let mut stdout = String::new();
                    let mut stderr = String::new();
                    
                    if let Some(mut stdout_handle) = child.stdout.take() {
                        let mut stdout_bytes = Vec::new();
                        stdout_handle.read_to_end(&mut stdout_bytes)
                            .map_err(|e| format!("读取标准输出失败: {}", e))?;
                        
                        // 尝试以 GBK 解码，如果失败则使用 UTF-8
                        stdout = decode_gbk_or_utf8(&stdout_bytes);
                    }
                    
                    if let Some(mut stderr_handle) = child.stderr.take() {
                        let mut stderr_bytes = Vec::new();
                        stderr_handle.read_to_end(&mut stderr_bytes)
                            .map_err(|e| format!("读取标准错误失败: {}", e))?;
                        
                        // 尝试以 GBK 解码，如果失败则使用 UTF-8
                        stderr = decode_gbk_or_utf8(&stderr_bytes);
                    }
                    
                    let success = status.success();
                    let exit_code = status.code();
                    
                    Ok(CommandResult {
                        success,
                        output: stdout,
                        error: if stderr.is_empty() { None } else { Some(stderr) },
                        exit_code,
                        new_working_dir: None,
                    })
                }
                Err(e) => Err(format!("执行命令失败: {}", e))
            }
        }
    }
}



#[tauri::command]
async fn get_system_info() -> Result<String, String> {
    use std::process::Command;
    
    #[cfg(target_os = "windows")]
    {
        let output = Command::new("cmd")
            .args(&["/C", "ver"])
            .output()
            .map_err(|e| format!("获取系统信息失败: {}", e))?;
        
        Ok(String::from_utf8_lossy(&output.stdout).to_string())
    }
    
    #[cfg(target_os = "linux")]
    {
        let output = Command::new("uname")
            .args(&["-a"])
            .output()
            .map_err(|e| format!("获取系统信息失败: {}", e))?;
        
        Ok(String::from_utf8_lossy(&output.stdout).to_string())
    }
    
    #[cfg(target_os = "macos")]
    {
        let output = Command::new("sw_vers")
            .output()
            .map_err(|e| format!("获取系统信息失败: {}", e))?;
        
        Ok(String::from_utf8_lossy(&output.stdout).to_string())
    }
}

#[tauri::command]
async fn show_window_after_load(window: tauri::Window) -> Result<(), String> {
    // 等待前端完全加载
    tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
    
    // 显示窗口
    window.show().map_err(|e| format!("显示窗口失败: {}", e))?;
    
    // 聚焦窗口
    window.set_focus().map_err(|e| format!("聚焦窗口失败: {}", e))?;
    
    println!("窗口已显示并聚焦");
    Ok(())
}

#[tauri::command]
async fn notify_page_ready(window: tauri::Window) -> Result<(), String> {
    // 前端通知页面已准备好，立即显示窗口
    window.show().map_err(|e| format!("显示窗口失败: {}", e))?;
    window.set_focus().map_err(|e| format!("聚焦窗口失败: {}", e))?;
    
    println!("页面已准备好，窗口已显示");
    Ok(())
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .plugin(tauri_plugin_shell::init())
        .invoke_handler(tauri::generate_handler![
            greet,
            read_directory,
            read_file,
            read_image_file,
            write_file,
            get_current_directory,
            select_folder,
            open_file_with_system,
            close_window,
            minimize_window,
            toggle_maximize_window,
            execute_command,
            get_system_info,
            show_window_after_load,
            notify_page_ready
        ])

        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
